/**
 * 
 */
package qy.jalgotrade.barfeed;

import java.time.ZonedDateTime;
import java.util.List;

import qy.jalgotrade.bar.Bar;
import qy.jalgotrade.bar.Bars;

/**
 * <pre>
 * This class is used by the optimizer module. The barfeed is already built on the server side, and
 * the bars are sent back to workers.
 * 
 * optimizer 模块专用: 原始 barfeed 由 server 管理 (迭代 bars), 并将其中所有 bars 分发个给所有 worker, worker 在
 * runStrategy() 时, 先使用 OptimizerBarFeed 封装接收到的 bars:
 * </pre>
 * 
 * @author c-geo
 *
 */
public class OptimizerBarFeed extends BaseBarFeed {

	private List<Bars> __bars;

	private int __nextPos;
	
	private int __nextPosDispatching;

	private ZonedDateTime __currDateTime;

	private ZonedDateTime __currDateTimeDispatching;

	private boolean __barsHaveAdjClose;

	/**
	 * 
	 * @param frequency
	 * @param instruments
	 * @param bars
	 * @throws Exception
	 */
	public OptimizerBarFeed(Bar.Frequency frequency, List<String> instruments, List<Bars> bars) throws Exception {

		this(frequency, instruments, bars, 0);
	}

	/**
	 * 
	 * @param frequency
	 * @param instruments
	 * @param bars
	 * @param maxLen
	 * @throws Exception
	 */
	public OptimizerBarFeed(Bar.Frequency frequency, List<String> instruments, List<Bars> bars, int maxLen)
	        throws Exception {

		super(frequency, maxLen);
		__nextPos = 0;
		__nextPosDispatching = 0;
		__currDateTime = null;
		__currDateTimeDispatching = null;

		for (String e : instruments) {
			registerInstrument(e);
		}
		__bars = bars;

		try {
			// TODO: Bar.getAdjClose() 返回空值的情况.
			__barsHaveAdjClose = !Double.isNaN(__bars.get(0).__getitem__(instruments.get(0)).getAdjClose());
		} catch (Exception e) {
			e.printStackTrace(); // TODO:
			__barsHaveAdjClose = false;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see qy.jalgotrade.barfeed.BaseBarFeed#getCurrentDateTime()
	 */
	@Override
	public ZonedDateTime getCurrentDateTime() {

		if (isDispatching()) {
			return __currDateTimeDispatching;
		} else {
			return __currDateTime;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see qy.jalgotrade.barfeed.BaseBarFeed#barsHaveAdjClose()
	 */
	@Override
	public boolean barsHaveAdjClose() {

		return __barsHaveAdjClose;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see qy.jalgotrade.barfeed.BaseBarFeed#getNextBars()
	 */
	@Override
	public Bars getNextBars() {

		Bars ret = null;
		if (__nextPos < __bars.size()) {
			ret = __bars.get(__nextPos);
			__currDateTimeDispatching = __currDateTime;
			__currDateTime = ret.getDateTime();
			__nextPosDispatching = __nextPos;
			__nextPos += 1;
		}
		return ret;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see qy.jalgotrade.event.Subject#start()
	 */
	@Override
	public void start() {

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see qy.jalgotrade.event.Subject#stop()
	 */
	@Override
	public void stop() {

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see qy.jalgotrade.event.Subject#join()
	 */
	@Override
	public void join() {

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see qy.jalgotrade.event.Subject#eof()
	 */
	@Override
	public boolean eof() {

		if (isDispatching()) {
			return __nextPosDispatching >= __bars.size();
		} else {
			return __nextPos >= __bars.size();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see qy.jalgotrade.event.Subject#peekDateTime()
	 */
	@Override
	public ZonedDateTime peekDateTime() {

		ZonedDateTime ret = null;
		int nextPos;
		if (isDispatching()) {
			nextPos = __nextPosDispatching;
		} else {
			nextPos = __nextPos;
		}
		if (nextPos < __bars.size()) {
			ret = __bars.get(nextPos).getDateTime();
		}
		return ret;
	}
}
